<?php

namespace App\Trip\Train\Order\Impl;

use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\Repositories\Interfaces\TrainOrdersRepositoryInterface;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Models\Train\TrainOrderTrain\TrainOrderTrain;
use App\Trip\Train\Order\Interfaces\TicketsChangeInterface;
use App\Trip\Train\Providers\PiaoChi\Order\OrderQuery;
use App\Trip\Train\Providers\PiaoChi\Passenger\CardType;
use App\Trip\Train\Providers\PiaoChi\Passenger\OrderPassenger;
use App\Trip\Train\Providers\PiaoChi\Passenger\PassengerType;
use App\Trip\Train\Providers\PiaoChi\TrainOrderService;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class PiaoChiTicketsChangeImpl implements TicketsChangeInterface
{

    private TrainOrder        $order;
    private TrainOrderService $order_service;

    public function __construct(TrainOrder $order)
    {
        $this->setTrainOrder($order);
        $this->setOrderService();
    }

    public function setTrainOrder(TrainOrder $order)
    {
        $this->order = $order;
    }

    public function setOrderService()
    {
        $this->order_service = new TrainOrderService();
    }

    /**
     * @throws Exception
     */
    public function change()
    {
        /**
         * @var TrainOrder      $order
         * @var TrainOrder|null $origin_order_info 改签原订单
         * @var int             $type 业务类型:0为出票、1为退票、2为改签、3为打印凭证
         */
        $lock_cache_key = "Train:Order:book:{$this->order->getOrderSn()}";
        if (!Redis::set($lock_cache_key, 1, 'nx', 'ex', config('trip.ttl.minutes'))) {
            throw new Exception("当前不允许执行改签操作,{$this->order->getOrderSn()}");
        }
        $order             = $this->order;
        $trainOrderRepo    = app(TrainOrdersRepositoryInterface::class);
        $origin_order_info = $order->getOriginOrderSn() ? $trainOrderRepo->getOrderInfo($order->getOriginOrderSn()) : null;
        if (!$origin_order_info) {
            Log::error("改签订单已支付，原订单未找到：{$order->getOrderSn()}");
            return;
        }
        $trip = $this->build_trips($order, $origin_order_info);
        try {
            $book = $this->order_service->ticketChanging([
                'trip'     => $trip,
                'order_sn' => $order->getOutOrderSn(),
                'order_id' => $origin_order_info->getOutOrderId(),
            ]);
        } catch (Exception $e) {
            throw new Exception("订单改签失败");
        }
        $res = json_encode($book, JSON_UNESCAPED_UNICODE);
        Log::info("Train:Order:change:order_sn:{$order->getOrderSn()},out_order_sn:{$order->getOutOrderSn()},{$res}");
        if ($book['order_id']) {
            $trainOrderRepo->saveOutOrderId($order, $book['order_id']);
        }
    }

    /**
     * @throws Exception
     */
    private function build_trips(TrainOrder $order, TrainOrder $origin_order_info)
    {
        // 获取最新状态
        $order->refresh();
        if ($order->isCancel()) {
            throw new Exception("改签订票异常拦截,订单已取消:{$order->getOrderSn()}");
        }
        /**
         * @var TrainOrderTrain     $main_train
         * @var TrainOrderTrain     $origin_main_train
         * @var TrainOrderPassenger $passenger
         */
        $date                      = $order->getTrainDate();
        $main_train                = $order->getMainTrain();
        $from_station              = $main_train->getFromName();
        $to_station                = $main_train->getToName();
        $train_code                = $main_train->getTrainCode();
        $passengers                = $order->getPassengers();
        $trip_passengers           = [];
        $origin_piaochi_order      = new OrderQuery($origin_order_info->getOutOrderId());
        $origin_piaochi_passengers = $origin_piaochi_order->getOrderPassengers($origin = true);
        $origin_date               = $origin_order_info->getTrainDate();
        $origin_main_train         = $origin_order_info->getMainTrain();
        $origin_from_station       = $origin_main_train->getFromName();
        $origin_to_station         = $origin_main_train->getToName();
        $origin_train_code         = $origin_main_train->getTrainCode();
        foreach ($passengers as $key => $passenger) {
            // 乘客原票数据
            $origin_piaochi_passenger = collect($origin_piaochi_passengers)
                ->where('sub_passenger_id', $passenger->subPassengerId())
                ->first();
            $rebuild                  = (new OrderPassenger($origin_piaochi_passenger['original']));
            $trip_passengers[$key]    = [
                "realname"         => $passenger->getTrueName(),
                "realcode"         => $passenger->getIdentityCode(),
                "realcode_guoji"   => "中华人民共和国",
                "cardtype"         => CardType::getCardType($passenger->getIdentityType()),
                "peopletype"       => PassengerType::getPeopleType($passenger->getPassengerType()),
                "seattip"          => $passenger->getSeatName(),
                "seatcodes"        => "",
                "email"            => "",
                "mobile"           => $passenger->getMobile(),
                "price"            => $passenger->getSeatPrice(),
                "paytype"          => $this->order_service::PAY_TYPE_ELECTRONIC,
                "info"             => '',
                "type"             => $order->isSnapUp() ? $this->order_service::ORDER_TYPE_SNAP_UP : $this->order_service::ORDER_TYPE_READY,
                "sub_passenger_id" => $passenger->subPassengerId(),
                // 原票数据
                "gaiticketcode"    => $rebuild->getOriginTicketNumber(),
                "gaiflytime"       => $origin_date,
                "gaifromcity"      => $origin_from_station,
                "gaitocity"        => $origin_to_station,
                "gaicarcode"       => $origin_train_code,
                "gaipaytype"       => $rebuild->getOriginPayType(),
                "gaiprice"         => $rebuild->getOriginPrice(),
                "gaiseatcode"      => $rebuild->getOriginSeatCode(),
                "gaiseatcodes"     => $rebuild->getOriginSeatCodes(),
                "gaiseattip"       => $rebuild->getOriginSeatTip(),
            ];
        }

        return [
            [
                "type"        => $this->order_service::BUSINESS_TYPE_CHANGE,
                "flytime"     => $date,
                "fromcity"    => $from_station,
                "tocity"      => $to_station,
                "carcode"     => $train_code,
                "info"        => "",
                "passenger"   => $trip_passengers,
                "sub_trip_id" => $order->getOrderSn(),
            ],
        ];
    }
}